/**
 * Ajax对象
 */
Fw.Ajax = function(config){
	Fw.apply(this, config);
    if(this.page === false){
        this.pageSize = 0;
    }
    if(this.maskEl){
        this.loadMask = new Fw.LoadMask({
            owner: Fw.isString(this.maskEl) ? $('#' + this.maskEl) : this.maskEl
        });
    }
	//call parent
	Fw.Ajax.superclass.constructor.call(this);
    //初始化事件
    this.initEvents();
	return this;
};
Fw.extend(Fw.Ajax, Fw.util.Observable, {
    /**
     * 每页条数 
     */
    pageSize: 10,
    /**
     * 显示页数 
     */
    pageLimit: 5,
    /**
     * 当前页 
     */
    currentPage: 1,
    currentPages: 1,
    /**
     * ajax默认配置
     */
	timeout: 30000,
    requestMethod: 'POST',
    dataType: 'json',
    async: true,
    /**
     * 初始化事件
     */
    initEvents: function(){
        //请求前
        this.on('beforerequest', this.onBeforeRequest, this);
        //请求成功
        this.on('success', this.onSuccess, this);
        //请求错误
        this.on('error', this.onFailure, this);
    },
    /**
     * 查询数据
     */
    query: function(page){
        this.setPage(page);
        var operation = Fw.Ajax.getRequestOperation.call(this, Fw.Ajax.QUERY_METHOD);
        Fw.Ajax.request.call(this, operation);
    },
    /**
     * 数据获取
     * @param {Array} arguments
     */
    get: function(){
        Fw.Ajax.parseOperationArguments(arguments, this, Fw.Ajax.GET_METHOD);
    },
    /**
     * 新增数据
     * @param {Array} arguments
     */
    insert: function(){
        Fw.Ajax.parseOperationArguments(arguments, this, Fw.Ajax.INSERT_METHOD);
    },
    /**
     * 删除数据
     * @param {Array} arguments
     */
    del: function(){
        Fw.Ajax.parseOperationArguments(arguments, this, Fw.Ajax.DELETE_METHOD);
    },
    /**
     * 更新数据
     * @param {Array} arguments
     */
    update: function(){
        Fw.Ajax.parseOperationArguments(arguments, this, Fw.Ajax.UPDATE_METHOD);
    },
    /**
     * 执行数据提交
     * @param {Array} arguments
     */
    execute: function(){
        Fw.Ajax.parseOperationArguments(arguments, this, Fw.Ajax.EXECUTE_METHOD);
    },
    /**
     * 请求前
     */
    onBeforeRequest: function(ajax, operation){
        if(this.action === Fw.Ajax.QUERY_METHOD && this.loadMask){
            this.loadMask.show();
        }
        this.operation = operation;
        if(this.action){
            return this.fireEvent('before' + this.action, this, operation.params, operation.url);
        }
    },
    /**
     * 请求成功
     */
    onSuccess: function(ajax, data, result, xhr){
        this.loadMask && this.loadMask.hide();
        this.action && this.fireEvent(this.action, this, data, result, xhr);
        delete this.operation;
    },
    /**
     * 请求错误
     */
    onFailure: function(ajax, status, textStatus, error, xhr){
        this.loadMask && this.loadMask.hide();
        this.action && this.fireEvent(this.action + 'error', this, status, textStatus, error, xhr);
        delete this.operation;
    },
    /**
     * 设置分页
     */
    setPage: function(page){
        if(Fw.isNumber(page)){
            page = page || 1;
            this.currentPage = page;
            this.options = {};
            this.options[Fw.Ajax.allowCountProperty] = !this.simplePage;
            this.options[Fw.Ajax.startParam] = (page - 1) * this.pageSize;
            this.options[Fw.Ajax.limitParam] = this.pageSize;
        }
    },
    /**
     * 设置请求参数
     * @param {} key
     * @param {} value
     * @param {} append
     */
    setParams: function(key, value, append){
        if(Fw.isObject(key)){
            this.params = key;
        }
        else {
            if(!this.params || append === false){
                this.params = {};
            }
            this.params[key] = value;
        }
        //
        if(this.operation){
            if(this.operation.isStructMessage){
                if(!this.operation.params.payload || append === false){
                    this.operation.params.payload = this.params;
                }
                else{
                    Fw.apply(this.operation.params.payload, this.params);
                }
            }
            else{
                if(append === false){
                    this.operation.params = this.params;
                }
                else{
                    Fw.apply(this.operation.params, this.params);
                }
            }
        }
    },
    /**
     * 返回请求参数
     * @param {} key
     */
    getParams: function(key){
        var params = null;
        if(this.operation){
            if(this.operation.isStructMessage){
                params = this.operation.params.payload;
            }
            else{
                params = this.operation.params;
            }
        }
        else{
            params = this.params;
        }
        //
        if(params){
            if(key){
                return params[key];
            }
            else{
                return params;
            }
        }
        return null;
    },
    /**
     * 清除请求参数
     * @param {} key
     */
    clearParams: function(key){
        if(this.operation){
            if(this.operation.isStructMessage){
                delete this.operation.params.payload;
            }
            else{
                delete this.operation.params;
            }
        }
        else{
            if(this.params){
                if(key){
                    delete this.params[key];
                }
                else{
                    delete this.params;
                }
            }
        }
    },
    /**
     * 设置排序方式
     * @param {} key
     * @param {} value
     * @param {} append
     */
    setSorts: function(key, value, append){
        if(Fw.isArray(key)){
            this.sort = key;
        }
        else {
            if(!this.sort || append === false){
                this.sort = [];
            }
            this.sort.push({
                property: key,
                direction: value || 'asc'
            });
        }
    },
    /**
     * 返回排序方式
     */
    getSorts: function(){
        return this.sort || null;
    },
    /**
     * 清除排序方式
     */
    clearSorts: function(){
        delete this.sort;
    }
});

/**
 * 常量和静态方法
 */
Fw.apply(Fw.Ajax, {
    /**
     * 请求方法 
     */
    GET_METHOD: 'GET',
    QUERY_METHOD: 'QUERY',
    INSERT_METHOD: 'INSERT',
    DELETE_METHOD: 'DELETE',
    UPDATE_METHOD: 'UPDATE',
    EXECUTE_METHOD: 'EXECUTE',
    /**
     * HTTP请求通道
     */
    //HTTP_CHANNEL: 'http://127.0.0.1:8080/ares-server/channel/http.do',//jsonP测试
    HTTP_CHANNEL: 'channel/http.do',
    /**
     * HTTP适配器SPI 
     */
    HTTP_ADAPTER_SPI: 'SPI/ADAPTER-HTTP',
    /**
     * SOCKET适配器SPI 
     */
    SOCKET_ADAPTER_SPI: 'SPI/ADAPTER-SOCKET',
    /**
     * 数据ROOT
     */
    rootProperty: 'result',
    /**
     * 记录条数
     */
    totalProperty: 'total',
    /**
     * 相应成功 
     */
    successProperty: 'success',
    /**
     * 成功消息 
     */
    messageProperty: 'message',
    /**
     * 错误消息 
     */
    errorMessageProperty: 'error',
    /**
     * 是否允许计算记录总数
     */
    allowCountProperty: 'allowCount',
    /**
     * 分页起始行
     */
    startParam: 'start',
    /**
     * 分页行数
     */
    limitParam: 'limit',
    /**
     * 请求
     */
    request: function(operation){
        if(this.fireEvent('beforerequest', this, operation) !== false){
            var url = operation.url;
            var data = operation.params;
            if(!Fw.isURL(url)){
                url = Fw.getBasePath() + url;
            }
            if(Fw.isObject(data) || Fw.isArray(data)){
                data = Fw.encode(data);
                if(data ==='{}') data = null;
            }
            // url += (url.indexOf('?') > 0 ? '&' : '?') + 't=' + new Date().getTime();
            var timestamp = (new Date()).getTime();
            if($.ajax.lastRequest){
                if(timestamp - $.ajax.lastRequest['timestamp'] < 1000 && data && $.ajax.lastRequest['data'] === data){
                    if(this.action === Fw.Ajax.QUERY_METHOD && this.loadMask){
                        this.loadMask.hide();
                    }
                    //防止重复提交
                    return;
                }
                else{
                    $.ajax.lastRequest['data'] = data;
                    $.ajax.lastRequest['timestamp'] = timestamp;
                }
            }
            else{
                $.ajax.lastRequest = {
                    data: data,
                    timestamp: timestamp
                };
            }
            //
            Fw.Ajax.doRequest.call(this, {
                url: url,
                data: data ? data.replace('${_t}', timestamp) : data///
            });
        }
    },
    /**
     * 执行请求
     * @param {} options
     */
    doRequest: function(options){
        Fw.applyIf(options, {
            type: this.requestMethod,
            dataType: this.dataType,
            async: this.async,
            timeout: this.timeout,
            contentType: 'application/json',
            success: Fw.bind(Fw.Ajax.onRequestSuccess, this),
            error: Fw.bind(Fw.Ajax.onRequestFailure, this)
        });
        
        //
        if(options.data){
            //加密
//            if(!!Fw.Security){
//                options.data = Fw.Security.encrypt(options.data);
//                if(Fw.Ajax.isJSONP()){
//                    options.data = encodeURIComponent(options.data);
//                }
//                else{
//                    options.data = encodeURI(options.data);
//                }
//            }
//            //不加密
//            else{
                options.data = encodeURIComponent(options.data);
//            }
        }
        else{
            options.data = null;
        }
        
        //
        if(Fw.Ajax.isJSONP()){
            Fw.apply(options, {
                type: 'GET',
                dataType: 'jsonp',
                jsonp: 'JSONPCallback',
                data: options.data ? 'data=' + options.data : null
            });
        }
        //
        $.ajax(options);
    },
    /**
     * 请求成功后
     * @param {} result
     * @param {} status
     * @param {} xhr
     */
    onRequestSuccess: function(result, status, xhr){
        try {
            var data;
            if (result) {
                if (result[Fw.Ajax.successProperty] !== true) {
                    xhr.status = -1;
                    Fw.Ajax.onRequestFailure.call(this, xhr, null, result[Fw.Ajax.errorMessageProperty] || result[Fw.Ajax.messageProperty]);
                    return;
                }
                data = result[Fw.Ajax.rootProperty];
                var total = result[Fw.Ajax.totalProperty];
                this.totalCount = Fw.isDefined(total) ? total : (Fw.isArray(data) ? data.length : Fw.isObject(data) ? 1 : 0);
            }
            else{
                data = null;
                result = null;
                this.totalCount = 0;
            }
            //
            this.fireEvent('success', this, data, result, xhr);
        }
        catch (e) {
            throw e;
        }
    },
    /**
     * 请求失败
     * @param {} xhr
     * @param {} textStatus
     * @param {} error
     */
    onRequestFailure: function(xhr, textStatus, error){
        //
        Fw.util.LoadMask.hide();
        //
        var errorDetail = xhr.responseText;
        var status = xhr.status;
        //
        switch(status) {
            //在其他设备登录
            case 403:
            //登陆超时，拒绝访问
            case 401://'Unauthorized'
                this.loadMask && this.loadMask.hide();
                var msg = status === 401 ? '您的登录信息已经超时，请重新登录！' : '您的账号已在其他设备登录，请重新登录！';
                Fw.Msg.info(msg, function(){
                    Fw.redirect(Fw.getBasePath() + '/login.html');
                });
                break;
            //服务器挂了或者取消请求
            case 0://'communication failure'
                Fw.Ajax.doRequest({
                    url: Fw.Ajax.getRequestURL(),
                    type: 'POST',
                    async: Fw.Ajax.isJSONP(),
                    timeout: 5000,
                    success: Fw.emptyFn,
                    error: Fw.bind(function(xhr, textStatus, error){
                        this.loadMask && this.loadMask.hide();
                        if(xhr.status === 0){
                            Fw.Msg.error('访问服务器失败！<br>请检查网络连接是否正常或者与系统管理员联系。');
                        }
                        else{
                            Fw.Ajax.onRequestFailure.call(this, xhr, textStatus, error);
                        }
                    }, this)
                });
                break;
            //其他，抛异常
            default:
                var allowErrorMsg = this.fireEvent('error', this, status, textStatus, error, xhr);
                if(allowErrorMsg !== false){
                    if(errorDetail){
                        Fw.Msg.show(
                            '错误',
                            'icon-error', 
                            '服务请求发生异常。<br>' + error, 
                            [
                                {id: 'ok', text: '确定', cls: 'btn-primary'},
                                {id: 'detail', text: '查看', cls: 'btn-danger'}
                            ],
                            function(type){
                                if(type === 'detail'){
                                    Fw.Window.show({
                                        title: '异常明细',
                                        html: errorDetail,
                                        buttons: [
                                            {text: '确定', cls: 'btn-primary'}
                                        ]
                                    });
                                }
                            }
                        );
                    }
                    else{
                        Fw.Msg.error('服务请求发生异常。<br>' + error);
                    }
                }
        }
    },
    /**
     * 返回Ajax请求配置
     * @param {Object} action
     */
    getRequestOperation: function(action){
        var operation;
        this.action = action;
        //自定义URL
        if(this.url){
            operation = {
                url: this.url,
                params: Fw.call(this.params)
            };
        }
        //Ares服务接口
        else{
            if(Fw.isDefined(this['method'])){
                this[action.toLowerCase() + 'Method'] = this['method'];
            }
            operation = {
                url: Fw.Ajax.getRequestURL(),
                params: Fw.Ajax.getRequestMessage.call(this, action),
                isStructMessage: true
            };
        }
        return operation;
    },
    /**
     * 返回Ajax请求报文（message）
     */
    getRequestMessage: function(action){
        //
        var spi, code;
        if(code = this.httpAdapter){
            spi = Fw.Ajax.HTTP_ADAPTER_SPI;
        }
        else if(code = this.socketAdapter){
            spi = Fw.Ajax.SOCKET_ADAPTER_SPI;
        }
        if(code){
            this.service = spi;
            action = Fw.Ajax.EXECUTE_METHOD;
            if(Fw.isArray(this.options) || Fw.isObject(this.options)){
                this.options = [{
                    _options: this.options,
                    _code: code
                }];
            }
            else{
                this.options = [code];
            }
        }
        //
        if(this.service){
            var message = {};
            var service = this.service.split('.');
            var method = action.toLowerCase();
            method = service.length > 1 ? service[1] : (this[method + 'Method'] || method || null);
            //原子服务
            if(method){
                var options = this.options || null;
                if(action === Fw.Ajax.QUERY_METHOD){
                    if(this.sort){
                        if(!options){
                            options = {};
                        }
                        options.sort = this.sort;
                    }
                }
                message.header = {
                    service: service[0],
                    method: method,
                    staticData: this.staticData || false,
                    options: options,
                    _t: '${_t}'//(new Date()).getTime()
                };
                delete this.options;
            }
            else{
                alert('未设置服务请求方法[method]');
                return null;
            }
            //请求参数
            message.payload = Fw.call(this.params) || null;
            //
            return message;
        }
        else{
            alert('未设置请求服务[service]');
            return null;
        }
    },
    /**
     * 返回Ajax请求路径
     */
    getRequestURL: function(){
        if(!Fw.isURL(Fw.Ajax.HTTP_CHANNEL)){
            Fw.Ajax.HTTP_CHANNEL = Fw.getBasePath() + '/' + Fw.Ajax.HTTP_CHANNEL;
        }
        return Fw.Ajax.HTTP_CHANNEL;
    },
    /**
     * 是否JSONP
     */
    isJSONP: function(){
        return Fw.Ajax.getRequestURL().indexOf(Fw.getBasePath()) !== 0;
    },
    /**
     * 解析请求参数（message.header.options）
     */
    parseOperationArguments: function(args, owner, action){
        var autoRequest = !!action;
        if(owner){
            owner.options = Array.prototype.slice.call(args, 0, args.length);
        }
        else{
            owner = args[args.length - 1];
            owner.options = Array.prototype.slice.call(args, 0, args.length - 1);
        }
        if(autoRequest){
            //自动提交请求
            Fw.Ajax.request.call(owner, Fw.Ajax.getRequestOperation.call(owner, action));
        }
        return owner;
    }
});

/**
 * Ajax工具类 
 */
Fw.util.Ajax = function(){
    //默认配置
    var config = {
        //default
        requestMethod: Fw.Ajax.prototype.requestMethod,
        dataType: Fw.Ajax.prototype.dataType,
        async: Fw.Ajax.prototype.async,
        timeout: Fw.Ajax.prototype.timeout,
        //接收Ajax事件
        fireEvent: function(){
            var type = arguments[0];
            var args = Array.prototype.slice.call(arguments, 2, arguments.length);
            switch(type){
                case 'success':
                    Fw.call(this.success, null, args);
                    break;
                case 'error':
                    Fw.call(this.failure, null, args);
                    break;
            }
        }
    };
    //设置请求配置
    var applyRequestConfig = function(){
        Fw.applyIf(this, config);
    };
    //执行请求
    var doRequest = function(args, action){
        args = Fw.Ajax.parseOperationArguments(args);
        applyRequestConfig.call(args);
        var operation = Fw.Ajax.getRequestOperation.call(args, action);
        Fw.Ajax.request.call(args, operation);
    };
    
    //工具方法
    return {
        /**
         * Ajax请求
         * @param {Object} args
         */
        request: function(args){
            Fw.util.Ajax.query(args);
        },
        /**
         * 查询数据
         * @param {Object} args
         */
        query: function(args){
            applyRequestConfig.call(args);
            var operation = Fw.Ajax.getRequestOperation.call(args, Fw.Ajax.QUERY_METHOD);
            Fw.Ajax.request.call(args, operation);
        },
        /**
         * 数据获取
         * @param {Array} arguments
         */
        get: function(){
            doRequest(arguments, Fw.Ajax.GET_METHOD);
        },
        /**
         * 新增数据
         * @param {Array} arguments
         */
        insert: function(){
            doRequest(arguments, Fw.Ajax.INSERT_METHOD);
        },
        /**
         * 删除数据
         * @param {Array} arguments
         */
        del: function(){
            doRequest(arguments, Fw.Ajax.DELETE_METHOD);
        },
        /**
         * 更新数据
         * @param {Array} arguments
         */
        update: function(){
            doRequest(arguments, Fw.Ajax.UPDATE_METHOD);
        },
        /**
         * 执行数据提交
         * @param {Array} arguments
         */
        execute: function(){
            doRequest(arguments, Fw.Ajax.EXECUTE_METHOD);
        }
    };
}();
